﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;

namespace Intersoft.Controls.TreeGridAssist
{
    public interface ITreeBuilder
    {
        IList<TreeGridNodeItem> BuildTree(TreeGridDataSource treeOwner, IList originalSource);
    }

    public class FlatTreeBuilder : ITreeBuilder
    {
        private Type _itemType;
        private PropertyInfo _pId;
        private PropertyInfo _pParentId;
        private TreeGridDataSource _treeOwner;
        private IList<FlatNode> _flatNodeList;
        private IDictionary<string, IList<FlatNode>> _parentIdDic;

        public string IdField { get; set; }
        public string ParentIdField { get; set; }
        public FlatTreeBuilder()
        {
            IdField = "Id";
            ParentIdField = "ParentId";
        }

        public FlatTreeBuilder(string idField, string parentIdField)
        {
            IdField = idField;
            ParentIdField = parentIdField;
        }

        public IList<TreeGridNodeItem> BuildTree(TreeGridDataSource treeOwner, IList originalSource)
        {
            _treeOwner = treeOwner;
            _flatNodeList = TurnToFlatNodeList(originalSource);
            IDictionary<string, string> idDic = GetIdDictionary(_flatNodeList);
            IList<TreeGridNodeItem> tree = GetRootNodes(treeOwner, _flatNodeList, idDic);
            _parentIdDic = GetParentIdDictionary(_flatNodeList);

            BuildRootNodesChildren(tree);
            return tree;
        }

        private IList<FlatNode> TurnToFlatNodeList(IList originalSource)
        {
            IList<FlatNode> flatNodeList = new List<FlatNode>();
            _itemType = originalSource[0].GetType();
            _pId = _itemType.GetProperty(IdField);
            _pParentId = _itemType.GetProperty(ParentIdField);

            for (int i = originalSource.Count - 1; i >= 0; i--)
            {
                object obj = originalSource[i];

                string id = _pId.GetValue(obj, null).ToString();
                string parentid = _pParentId.GetValue(obj, null).ToString();
                flatNodeList.Add(new FlatNode(id, parentid, obj));
            }

            return flatNodeList;
        }

        private IDictionary<string, string> GetIdDictionary(IList<FlatNode> flatNodeList)
        {
            IDictionary<string, string> dic = new Dictionary<string, string>();
            foreach (FlatNode n in flatNodeList)
            {
                dic.Add(n.Id, "");
            }

            return dic;
        }

        private IDictionary<string, IList<FlatNode>> GetParentIdDictionary(IList<FlatNode> flatNodeList)
        {
            IDictionary<string, IList<FlatNode>> dic = new Dictionary<string, IList<FlatNode>>();
            foreach (FlatNode n in flatNodeList)
            {
                IList<FlatNode> nodes = null;
                if (!dic.TryGetValue(n.ParentId, out nodes))
                {
                    nodes = new List<FlatNode>();     
                    dic.Add(n.ParentId, nodes);               
                }
                nodes.Insert(0, n);
            }
            return dic;
        }
        
        private IList<TreeGridNodeItem> GetRootNodes(TreeGridDataSource treeOwner, IList<FlatNode> flatNodeList, IDictionary<string, string> dictionary)
        {
            IList<TreeGridNodeItem> tree = new List<TreeGridNodeItem>();
            for (int i = flatNodeList.Count - 1; i >= 0; i--)
            {
                FlatNode n = flatNodeList[i];
                if (string.IsNullOrEmpty(n.ParentId) || !dictionary.ContainsKey(n.ParentId))
                {
                    tree.Add(new TreeGridNodeItem(treeOwner, n.Id, n.Item));
                    flatNodeList.RemoveAt(i);
                }
            }

            return tree;
        }

        private void BuildRootNodesChildren(IList<TreeGridNodeItem> tree)
        {
            foreach (TreeGridNodeItem n in tree)
            {
                BuildNode(n);
            }
        }

        private void BuildNode(TreeGridNodeItem parentNodeItem)
        {
            //Type itemType = parentNodeItem.Item.GetType();
            //PropertyInfo pId = itemType.GetProperty(IdField);
            //string parentNodeItemId = pId.GetValue(parentNodeItem.Item, null).ToString();
            //
            //for (int i = _flatNodeList.Count - 1; i >= 0; i--)
            //{
            //    FlatNode n = _flatNodeList[i];
            //    if (n.ParentId == parentNodeItem.Id)
            //    {
            //        parentNodeItem.AddChild(new TreeGridNodeItem(_treeOwner, n.Id, n.Item));
            //        _flatNodeList.RemoveAt(i);
            //    }
            //}

            IList<FlatNode> nodes = null;
            if (_parentIdDic.TryGetValue(parentNodeItem.Id, out nodes))
            {
                foreach (FlatNode n in nodes)
                {
                    parentNodeItem.AddChild(new TreeGridNodeItem(_treeOwner, n.Id, n.Item));
                }
            }            

            foreach (TreeGridNodeItem node in parentNodeItem.Children)
            {
                BuildNode(node);
            }
        }
    }

    public class FlatNode
    {
        public string Id { get; set; }
        public string ParentId { get; set; }
        public object Item { get; set; }
        public FlatNode(string id, string parentId, object item)
        {
            Id = id;
            ParentId = parentId;
            Item = item;
        }
    }
}
